home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
graphics
/
fig2mfpic
/
graphbase.mf
< prev
next >
Wrap
Text File
|
1994-06-15
|
23KB
|
1,229 lines
%%% Author: Geoffrey Tobin.
%%% Address: G.Tobin@ee.latrobe.edu.au
%%%
%%% File: graphbase.mf
%%%
mode_setup;
message "graphbase 0.2 fig 2a - 13:32 GMT +10 Thu 16 June 1994";
% set up local environment
def mfpicenv =
begingroup
% miscellaneous utilities
% gt - op_pair operates with "op"
% on both parts of a pair p.
save op_pair;
vardef op_pair (text op) (expr p) =
(op (xpart p), op (ypart p))
enddef;
save floorpair, ceilingpair;
def floorpair = op_pair (floor) enddef;
def ceilingpair = op_pair (ceiling) enddef;
% gt - Should there be more error-checking,
% eg of types, in these utility routines?
% That would slow them down.
% gt - textpairs converts the text t into the
% array of n pairs, pts, that it contains.
save textpairs;
def textpairs (text t) (suffix pairs_, n_) =
n_ := 0;
for q=t:
pairs_[incr n_] := q;
endfor;
enddef;
% gt - Watch out! Need to ensure that "p_", etc.,
% don't clash with any name in the passed text "t".
% That's a nasty error to trace!
%
% A name conflict between local variables and variables
% in a text parameter is especially likely in low-level
% utility macros, such as minpair, maxpair and corner.
%
% Unfortunately, we can't *ensure* it won't happen.
% So I appended the underscore to reduce the
% probability of that happening.
%
% Evidently that's why Knuth uses "u_" in "max" and
% "min" in "plain.mf".
% gt - corner may be used for finding
% a corner of the bounding box of the
% set of points listed in u and t.
% Other uses may be imaginable. (?)
save corner;
vardef corner (text xop) (text yop)
(expr u)(text t) =
save p_;
pair p_;
p_ := u;
for q=t:
p_ := (xop (xpart p_, xpart q),
yop (ypart p_, ypart q));
endfor;
p_
enddef;
% gt - bottom right, bottom right,
% top left, top right corners.
save blpair, brpair, tlpair, trpair;
def blpair = corner (min) (min) enddef;
def brpair = corner (max) (min) enddef;
def tlpair = corner (min) (max) enddef;
def trpair = corner (max) (max) enddef;
def minpair = blpair enddef;
def maxpair = trpair enddef;
% setup
% gt - sets the graphics coordinates.
save bounds,
xneg,xpos,yneg,ypos;
def bounds(expr a,b,c,d) =
xneg:=a;
xpos:=b;
yneg:=c;
ypos:=d;
enddef;
% conversion
save xconv;
def xconv(expr xvalue) =
((xvalue-xneg)/(xpos-xneg))*w
enddef;
save unxconv;
def unxconv(expr pvalue) =
((pvalue/w)*(xpos-xneg)+xneg)
enddef;
save yconv;
def yconv(expr yvalue) =
((yvalue-yneg)/(ypos-yneg))*h
enddef;
save ztr;
transform ztr;
save setztr;
def setztr =
ztr:=identity
shifted -(xneg,yneg)
xscaled (w/(xpos-xneg))
yscaled (h/(ypos-yneg));
enddef;
% pen width
% in pixel coordinates
save penwd;
newinternal penwd;
interim penwd := 0.5pt;
% arrowheads
% in pixel coordinates
% hdwdr = arrowhead's ratio of width to length,
% hdten = tension used in drawing its barbs.
save hdwdr, hdten;
newinternal hdwdr, hdten;
interim hdwdr := 1;
interim hdten := 1;
% draw an arrowhead.
save head, p,side;
def head(expr front, back, width, t) =
pair p[], side;
side := (width/2) *
((front-back) rotated 90);
p1 := back + side;
p2 := back - side;
draw front{back-front}..tension t..p1;
draw front{back-front}..tension t..p2;
enddef;
% draw an arrowhead of length hlen
% for a path f.
save headpath, p;
def headpath(expr f,hlen) =
pair p[];
p2:=point infinity of f;
p1:=direction infinity of f;
if p1<>(0,0):
head(p2,p2-(hlen*unitvector(p1)),
hdwdr,hdten);
fi;
enddef;
% shading and hatching routines
% in pixel coordinates
% gt - modified onedot based on
% plain metafont's "drawdot".
% Used in stipple shading.
%
% Note:
% currentpen_path, def_pen_path_,
% t_, and penspeck are defined
% in plain metafont ("plain.mf"
% or "plain.base").
save onedot;
def onedot(expr p)(suffix v) =
if unknown currentpen_path:
def_pen_path_
fi;
addto v
contour currentpen_path
shifted p.t_
withpen penspeck
enddef;
% gt - draw path f in picture v.
% ("onepath" is the old "onedot",
% but f is intended to be a general path.)
% Used, eg, in hatching and in drawpaths.
save onepath;
def onepath (expr f) (suffix v) =
addto v doublepath f
withpen currentpen;
enddef;
% gt - Paths must be continuous - I think
% - but using suffix, we can pass arrays
% of paths.
%
% My eventual goal is to do as much as
% feasible, and memory-affordable, in
% graphics coordinates, so we can rotate
% and otherwise transform sets of paths
% before drawing.
% gt - draw the n paths f[] in picture v.
save drawpaths;
def drawpaths (expr n) (suffix f, v) =
for i=1 upto n:
onepath (f[i], v);
endfor;
enddef;
% clip picture v to interior of path f.
save clip;
vardef clip(expr f)(suffix v) =
save vt;
picture vt;
vt:=v;
cull vt keeping (1,infinity);
addto vt contour f;
cull vt keeping (2,infinity);
vt
enddef;
% gt - find bounding box of path f.
save boundingbox, p;
def boundingbox (expr f) (suffix ll, ur) =
ur := ll := point 0 of f;
pair p[];
for i=0 upto length f:
p0 := point i of f;
p1 := precontrol i of f;
p2 := postcontrol i of f;
ll := minpair (ll, p0, p1, p2);
ur := maxpair (ur, p0, p1, p2);
endfor;
enddef;
% gt - shading.
% gt - I'm not so happy with dot densities
% over a uniform range.
% Here's code to approximate what may
% be the human eye's light sensitivity.
%
% Mind you, this sort of stuff is done much
% faster in C.
save exp;
vardef exp (expr x) =
mexp (256 * x)
enddef;
% graya scales the spacing sp;
% grayb scales the graylevel g.
save graya, grayb;
newinternal graya, grayb;
% initial values of gray parameters.
interim graya := 0.5 pt;
interim grayb := 3/20;
% setgraypars sets gray parameters.
% experimentation is recommended.
save setgraypars;
def setgraypars (expr a, b) =
graya := a;
grayb := b;
enddef;
% gt - grayspace gives the dot spacing
% for graylevel g.
%
% Not sure how this model performs.
save grayspace;
vardef grayspace (expr g) =
if g <= 1: % white
infinity
elseif g >= 21: % black
0
else: % gray
graya / (1 - exp (-g * grayb))
fi
enddef;
% gt - stipple upright box with lower left
% at ll, upper right at ur, in picture v;
% 2sp is dot spacing (rows offset by sp).
%
% NB: "stipple" means "shade with dots",
% if I understand my English dictionary.
%
% Thomas Leathrum devised the trick whereby
% the dots are arranged on a regular grid
% of mesh size sp by sp with the pixel
% origin as one crosspoint. This ensures
% that objects shaded with the same stipple
% density may be cleanly overlaid.
save shadebox, sll, mn, m, n, twosp, p;
def shadebox (expr sp, ll, ur) (suffix v) =
pair sll;
sll:=sp*(ceilingpair(ll/sp));
pair mn;
mn:=floorpair((ur-sll)/sp);
m:=xpart mn;
n:=ypart mn;
twosp:=2sp;
v:=nullpicture;
pair p[];
p2:=sll;
for i=0 upto m:
p3:=p2 if odd i: +(0,sp) fi;
for j=0 upto n:
if (not odd (i+j)):
onedot (p3, v);
p3:=p3+(0,twosp);
fi;
endfor;
p2:=p2+(sp,0);
endfor;
enddef;
% stipple interior of closed path f;
% if spacing not positive, fill.
save shadepath, ll, ur, v;
def shadepath (expr sp, f) =
if not cycle f: ;
elseif sp<=0:
fill f;
elseif sp < infinity:
pair ll, ur;
boundingbox (f, ll, ur);
picture v;
shadebox (sp, ll, ur, v);
addto currentpicture
also clip(f,v);
fi;
enddef;
% gt - hatch an upright box in picture v,
% with line separation sep x sep.
%
% Notice the similarity to shadebox.
save hatchbox, llx, lly, urx, ury, sll,
mn, m, n, f;
def hatchbox (expr sep, ll, ur) (suffix v) =
llx := xpart ll;
lly := ypart ll;
urx := xpart ur;
ury := ypart ur;
pair sll;
sll := sep * ceilingpair (ll/sep);
pair mn;
mn := floorpair ((ur-sll)/sep);
m := xpart mn;
n := ypart mn;
v := nullpicture;
path f;
f := (xpart sll, lly)--(xpart sll, ury);
for i=0 upto m:
onepath (f, v);
f := f translated (sep, 0);
endfor;
f := (llx, ypart sll)--(urx, ypart sll);
for j=0 upto n:
onepath (f, v);
f := f translated (0, sep);
endfor;
enddef;
save hatchpath, ll, ur, v;
def hatchpath (expr sep, f) =
if not cycle f: ;
elseif sep<=0:
fill f;
elseif sep < infinity:
pair ll, ur;
boundingbox (f, ll, ur);
picture v;
hatchbox (sep, ll, ur, v);
addto currentpicture
also clip (f, v);
fi;
enddef;
% gt - shading & hatching macros
% with a syntax like draw, fill,
% unfill and erase.
% sp, sep are in pixel coords,
% f in graphics coordinates;
% f is transformed transparently.
save shade;
def shade (expr sp) expr f =
shadepath (sp, f transformed ztr);
enddef;
save hatch;
def hatch (expr sep) expr f =
hatchpath (sep, f transformed ztr);
enddef;
% gt - common combinations.
save drawshade;
def drawshade (expr sp) expr f =
draw f transformed ztr;
shade (sp) f;
enddef;
save drawhatch;
def drawhatch (expr sep) expr f =
draw f transformed ztr;
hatch (sep) f;
enddef;
% * rest of macros start in graphing
% coordinates but convert to pixel
% to draw
% * variables ending in "_px"
% converted to pixel
% * exceptions are the TeX dimensions
% here called:
% ptwd, hlen, dlen, slen, len, sp, sep
% all of which are in pixel coordinates
% * macros beginning with "mk" operate
% entirely in graphing coordinates
% general path construction
save mkpath;
vardef mkpath(expr smooth, cyclic, n)
(suffix pts) =
if smooth:
if cyclic:
pts[1]{pts[2]-pts[n]}
else:
pts[1]
fi
for i=2 upto n-1:
..pts[i]{pts[i+1]-pts[i-1]}
endfor
if cyclic:
..pts[n]{pts[1]-pts[n-1]}..cycle
else:
..pts[n]
fi
else:
for i=1 upto n-1:
pts[i] --
endfor
pts[n]
if cyclic:
-- cycle
fi
fi
enddef;
% points, lines, and arrows
save pointd, p;
def pointd(expr a,ptwd) =
pair p_px;
p_px:=a transformed ztr;
fill fullcircle scaled ptwd shifted p_px;
enddef;
save line;
def line(expr a,b) =
draw (a..b) transformed ztr;
enddef;
% gt - arrowpath draws path f
% with an arrowhead;
% hlen is in pixel coordinates;
% f is in graphics coords;
% f is transformed transparently.
% Compare shade, hatch, etc.,
% and contrast shadepath.
save arrowpath, f_px;
def arrowpath (expr hlen) expr f =
path f_px;
f_px := f transformed ztr;
draw f_px;
headpath (f_px, hlen);
enddef;
% gt - arrow now uses arrowpath.
save arrow;
def arrow(expr tl,hd,hlen) =
arrowpath (hlen) tl..hd ;
enddef;
% gt - "px" was too frequent
% in dottedline, and made the code
% hard to read, so I've deleted it.
% Only a and b are in graphics coords.
save dottedline,
p, v, l, delta, n;
def dottedline (expr a, b, dlen, slen) =
pair p[];
p1 := a transformed ztr;
p3 := b transformed ztr;
l := length (p3-p1);
if (l > 2dlen) and
(dlen >= 0) and (slen >= 0):
else:
pair v;
v := unitvector (p3-p1);
n := floor ((l+slen-dlen) / (dlen+slen));
delta := (l-dlen) / n - (dlen+slen);
for i=1 upto n:
p2 := p1 + dlen * v;
draw p1..p2;
p1 := p2 + (slen+delta) * v;
endfor;
fi;
draw p1..p3;
enddef;
save dottedarrow;
def dottedarrow(expr tl,hd,dlen,
slen,hlen) =
dottedline(tl,hd,dlen,slen);
headpath((tl..hd) transformed ztr,hlen);
enddef;
% axes and axis marks
save axes;
def axes(expr hlen) =
arrow((0,yneg),(0,ypos),hlen);
arrow((xneg,0),(xpos,0),hlen);
enddef;
save xmarks;
def xmarks(expr len)(text t) =
for a=t:
draw (xconv(a),yconv(0)-(len/2))..
(xconv(a),yconv(0)+(len/2));
endfor;
enddef;
save ymarks;
def ymarks(expr len)(text t) =
for a=t:
draw (xconv(0)-(len/2),yconv(a))..
(xconv(0)+(len/2),yconv(a));
endfor;
enddef;
% upright rectangles
save mkrect;
vardef mkrect(expr ll,ur) =
ll--(xpart ll,ypart ur)--
ur--(xpart ur,ypart ll)--cycle
enddef;
save rect;
def rect(expr ll,ur) =
draw mkrect(ll,ur) transformed ztr;
enddef;
save dottedrect;
def dottedrect(expr ll,ur,dlen,slen) =
dottedline(ll,(xpart ll,ypart ur),
dlen,slen);
dottedline((xpart ll,ypart ur),ur,
dlen,slen);
dottedline(ur,(xpart ur,ypart ll),
dlen,slen);
dottedline((xpart ur,ypart ll),ll,
dlen,slen);
enddef;
save block;
def block(expr ll,ur) =
fill mkrect(ll,ur) transformed ztr;
enddef;
% gt - rectshade now uses shade.
save rectshade;
def rectshade(expr sp,ll,ur) =
shade (sp) mkrect (ll, ur);
enddef;
% circles and ellipses
save mkellipse;
vardef mkellipse(expr center,radx,rady,
angle) =
save t;
transform t;
t := identity
xscaled (2 * radx)
yscaled (2 * rady)
rotated angle
shifted center;
fullcircle transformed t
enddef;
save ellipse;
def ellipse(expr center,radx,rady,
angle) =
draw
mkellipse(center,radx,rady,angle)
transformed ztr;
enddef;
save circle;
def circle(expr center,rad) =
ellipse(center,rad,rad,0);
enddef;
% gt - ellshade now uses shade.
save ellshade;
def ellshade (expr sp, center,
radx, rady, angle) =
shade (sp)
mkellipse (center, radx, rady, angle);
enddef;
save circshade;
def circshade(expr sp, center,rad) =
ellshade(sp,center,rad,rad,0);
enddef;
% circular arcs
% gt - mkarc now calculates
% n using ceiling, not floor;
% and saves theta, not i.
save mkarc;
vardef mkarc(expr center,from,sweep) =
pair p,q;
path f;
if sweep=0: f:=from
else:
n:=floor(abs(sweep)/45)+1;
if n<3: n:=3; fi;
theta:=sweep/(n-1);
f:=p:=from;
for i:=2 upto n:
p:=p rotatedabout (center,theta);
q:=p-center; q:=q rotated 90;
if theta<0: q:=-q; fi;
f:=f..p{unitvector q};
endfor;
fi;
f
enddef;
% gt - note that when sweep is a multiple
% of 360 degrees, disp is logically
% infinite, not zero; then the center is
% at infinity. In practice, arccenter
% ought not to be called in that case.
save arccenter;
vardef arccenter(expr from,to,sweep)=
if from=to:
from
else:
pair midpt;
midpt:=(0.5)[from,to];
if (sweep mod 360)=0:
midpt
else:
disp:=cosd(sweep/2)/sind(sweep/2);
midpt+(disp*((to-from) rotated 90)/2)
fi
fi
enddef;
% gt - mkarcto makes an arc given two points
% on the arc and the sweep angle.
% If sweep is a multiple of 360 degrees,
% then the arc is a straight line;
% if sweep is also nonzero, then that
% line should be infinite, but I use
% from--to instead.
save mkarcto;
vardef mkarcto(expr from,to,sweep) =
pair center;
center:=arccenter(from,to,sweep);
(mkarc(center, from, sweep))
enddef;
% gt - arc now uses mkarcto.
save arc;
def arc(expr from,to,sweep) =
draw mkarcto (from, to, sweep)
transformed ztr;
enddef;
% gt - arcarrow now uses mkarcto
% and arrowpath.
save arcarrow;
def arcarrow(expr hlen,from,to,sweep) =
arrowpath (hlen) mkarcto (from, to, sweep);
enddef;
% gt - mkchordto makes a cyclic path from
% the arc from "from" to "to" with a sweep
% angle of "sweep", and its chord from
% "to" to "from".
save mkchordto;
vardef mkchordto (expr from, to, sweep) =
mkarcto (from, to, sweep) -- cycle
enddef;
% gt - arcshade now uses mkchordto
% and shade.
save arcshade;
def arcshade(expr sp,from,to,sweep) =
shade (sp) mkchordto (from, to, sweep);
enddef;
% gt - three-point arcs.
save mkarcthree;
vardef mkarcthree (expr first, second, third) =
sweep:=2*(angle(third-second)-angle(second-first));
sweep:=sweep mod 720;
if sweep > 360: sweep:=sweep-720; fi
critical:=5;
if abs(sweep) <= critical: % center may blow out
pair p[]; p1:=first; p2:=second; p3:=third;
mkpath(true,false,3,p)
else:
pair m[], d[], center;
m1:=(0.5)[first,second]; d1:=(second-first) rotated 90;
m2:=(0.5)[second,third]; d2:=(third-second) rotated 90;
center = m1+whatever*d1 = m2+whatever*d2;
mkarc(center,first,sweep)
fi
enddef;
save arcthreecenter;
vardef arcthreecenter (expr first, mid, last) =
save c, m, d;
pair c, m[], d[];
d1 := (mid - first) rotated 90;
d2 := (last - mid) rotated 90;
m1 := 0.5 [first, mid];
m2 := 0.5 [mid, last];
c = m1 + whatever * d1 = m2 + whatever * d2;
c
enddef;
save arcthree;
def arcthree (expr first, mid, last) =
draw mkarcthree (first, mid, last) transformed ztr;
enddef;
save arcthreearrow;
def arcthreearrow (expr hlen, first, mid, last) =
arrowpath (hlen) mkarcthree (first, mid, last);
enddef;
% modified polar coordinates
% gt - mklinedir makes a path from point "a"
% to a point displaced "len" in direction "theta"
% from "a".
save mklinedir;
vardef mklinedir (expr a, theta, len) =
a -- (a + len * (dir theta))
enddef;
% gt - linedir now uses mklinedir.
save linedir;
def linedir(expr a,theta,len) =
draw mklinedir (a, theta, len)
transformed ztr;
enddef;
% gt - arrowdir now uses mklinedir
% and arrowpath.
save arrowdir;
def arrowdir(expr hlen,a,theta,len) =
arrowpath (hlen)
mklinedir (a, theta, len);
enddef;
% gt - mkarcth makes an arc path with
% given center, radius "rad", initial
% angle "frtheta", and final angle
% "totheta".
save mkarcth;
vardef mkarcth (expr center,
frtheta, totheta, rad) =
save from;
pair from;
from := center + rad * (dir frtheta);
mkarc (center, from, totheta-frtheta)
enddef;
% gt - arcth now uses mkarcth.
save arcth;
def arcth(expr center,
frtheta,totheta,rad) =
draw mkarcth (center, frtheta,
totheta, rad)
transformed ztr;
enddef;
% gt - arcth now uses mkarcth
% and arrowpath.
save arctharrow;
def arctharrow(expr hlen,center,
frtheta,totheta,rad) =
arrowpath (hlen)
mkarcth (center, frtheta,
totheta, rad);
enddef;
% gt - mkwedge makes a wedge-shaped path
% with apex at "center", radius "rad",
% initial angle "frtheta", and final angle
% "totheta".
save mkwedge;
vardef mkwedge (expr center, frtheta, totheta, rad) =
center -- mkarcth (from, frtheta, totheta, rad)
-- cycle
enddef;
% gt - wedge draws a sector of a circle.
save wedge;
def wedge (expr center, frtheta, totheta, rad) =
draw mkwedge (center, frtheta, totheta, rad)
transformed ztr;
enddef;
% gt - wedgeshade now uses mkwedge and shade.
save wedgeshade;
def wedgeshade (expr sp, center,
frtheta, totheta, rad) =
shade (sp) mkwedge (center, frtheta, totheta, rad);
enddef;
% gt - drawshadewedge draws and shades a wedge.
save drawshadewedge;
def drawshadewedge (expr sp, center,
frtheta, totheta, rad) =
draw mkwedge (center, frtheta, totheta, rad)
transformed ztr;
shade (sp) mkwedge (center, frtheta, totheta, rad);
enddef;
% curves
% gt - watch out for that "text containing a local
% variable's name" conflict! I dearly wish that
% weren't a danger.
% Perhaps it's not so likely at the level of "mkcurve",
% as the "mk" macros are often fed numeric constants.
save mkcurve;
vardef mkcurve(expr smooth,cyclic)
(text t) =
save n_, p_;
pair p_[];
textpairs (t) (p_, n_);
mkpath(smooth,cyclic,n_,p_)
enddef;
save curve;
def curve(expr smooth,cyclic)
(text t) =
draw mkcurve(smooth,cyclic,t)
transformed ztr;
enddef;
% gt - curvedarrow now uses arrowpath.
save curvedarrow;
def curvedarrow(expr smooth,hlen)
(text t) =
arrowpath (hlen)
mkcurve (smooth, false, t);
enddef;
% shading of cyclic curves
% gt - cycleshade now uses shade.
save cycleshade;
def cycleshade(expr sp,smooth)(text t) =
shade (sp) mkcurve (smooth,true,t);
enddef;
% gt - interpolated splines with controls.
% gt - mkipath uses the interpolation points,
% p[], and the left and right control points,
% l[] and r[].
% Observe that for cyclic I-splines, l[n] is
% used, not l1, though they are equal; this
% simplifies the algorithm.
save mkipath;
vardef mkipath (expr closed, n)
(suffix p, l, r) =
for i=1 upto n-1:
p[i]..controls r[i] and l[i+1]..
endfor
if closed:
cycle
else:
p[n]
fi
enddef;
% gt - mkisplineA uses the I-spline data,
% in the order that Fig 2.1 gives them,
% points line pl and control line cl,
% stores them in p[], l[] and r[],
% then calls mkipath.
%
% pl should have the form:
% (x1,y1) ... (xn,yn)
% and cl the form:
% (lx1,ly1) (rx1,ry1) ... (lxn,lyn) (rxn,ryn)
% which reflect how Fig outputs its data.
%
% Don't feed it the "9999 9999", please!
%
% Perhaps the input should be massaged by a
% preprocessor program (e.g. in C), to separate
% the initially interleaved left and right control
% points, before being given to graphbase?
% That would simplify mkisplineA, and run faster.
save mkisplineA;
vardef mkisplineA (expr closed)
(text pl) (text cl) =
save p, l, r, n, i, isleft;
pair p[], l[], r[];
boolean isleft;
textpairs (pl) (p, n);
i := 1;
isleft := true;
for b=cl:
if isleft:
l[i] := b;
isleft := false;
else:
r[i] := b;
i := i+1;
isleft := true;
fi;
endfor;
mkipath (closed, n, p, l, r)
enddef;
% gt - mkisplineB uses the points line,
% and the separated left and right controls.
%
% See how much simpler this is than
% mkisplineA.
save mkisplineB;
vardef mkisplineB (expr closed)
(text pl) (text lc) (text rc) =
save p, l, r, n, i;
pair p[], l[], r[];
textpairs (pl) (p, n);
textpairs (lc) (l, i);
textpairs (rc) (r, i);
mkipath (closed, n, p, l, r)
enddef;
% gt - the usual variations.
%
% These use mkisplineA. I'd prefer
% mkisplineB.
% draw an interpolated spline,
% with points line pl and interleaved
% control line cl.
save ispline;
def ispline (expr closed)
(text pl) (text cl) =
draw mkisplineA (closed) (pl) (cl)
transformed ztr;
enddef;
save isplinearrow;
def isplinearrow (expr hlen, closed)
(text pl) (text cl) =
arrowpath (hlen)
mkisplineA (closed) (pl) (cl);
enddef;
% gt - isplineshade assumes that the
% I-spline is closed.
save isplineshade;
def isplineshade (expr sp)
(text pl) (text cl) =
shade (sp)
mkisplineA (true) (pl) (cl);
enddef;
% functions
% gt - better be on the safe side with
% the function text, so use "_" on local
% variables in "mkfcn".
save mkfcn;
vardef mkfcn(expr smooth,bmin,bmax,bst)
(suffix bv)(text fcnpr) =
save p_, i_;
pair p_[];
i_ := 0;
for bv=bmin step bst
until bmax+(bst/2):
p_[incr i_] := fcnpr;
endfor;
mkpath (smooth, false, i_ , p_)
enddef;
save function;
def function(expr smooth,xmin,xmax,st)
(text fx) =
draw mkfcn (smooth, xmin, xmax, st,
x, (x,fx))
transformed ztr;
enddef;
save parafcn;
def parafcn(expr smooth,tmin,tmax,st)
(text ft) =
draw mkfcn (smooth, tmin, tmax, st,
t, ft)
transformed ztr;
enddef;
% gt - mksfn constructs a path from
% two functions and the verticals
% at either side.
%
% mksfn is used by shadefcn.
save mksfn;
vardef mksfn (expr smooth, xmin, xmax, st)
(text fcni) (text fcnii) =
mkfcn(smooth,xmin,xmax,st,x,(x,fcni))
--
reverse
mkfcn(smooth,xmin,xmax,st,x,(x,fcnii))
-- cycle
enddef;
% gt - description:
% shadefcn shades between two functions over
% the range xmin to xmax, stepping by st,
% with dot spacing sp.
% it does not draw the functions.
% gt - shadefcn now uses mksfn.
% I don't see the connection between the dot
% spacing sp and the function step size st.
save shadefcn, st;
def shadefcn(expr sp, xmin, xmax)
(text fcni)(text fcnii) =
st := unxconv (sp);
shade (sp)
mksfn (false, xmin, xmax, st) (fcni) (fcnii);
enddef;
% gt - drawshadefcn draws both functions fcni
% and fcnii, and shades between them.
save drawshadefcn;
def drawshadefcn (expr sp, smooth, xmin, xmax, st)
(text fcni) (text fcnii) =
function (smooth, xmin, xmax, st) (fcni);
function (smooth, xmin, xmax, st) (fcnii);
shadefcn (sp, xmin, xmax) (fcni) (fcnii);
enddef;
enddef; % mfpicenv
def endmfpicenv =
endgroup;
enddef;
% end graphbase.mf